/**
    Copyright (c) 2021 LiuBingyi
    reverse-polish-notation-by-csharp is licensed under Mulan PSL v2.
    You can use this software according to the terms and conditions of the Mulan PSL v2.
    You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2
    THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
    EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
    MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
    See the Mulan PSL v2 for more details.
 */

using System.Text;
using System.Diagnostics.CodeAnalysis;

namespace Calculation
{
    public delegate CalculateSymbol Action(CalculateSymbol[] variables);
    public struct CalculateSymbol
    {
        public readonly string symbol;
        public readonly byte level;
        public readonly byte requirePara;
        public readonly Action? action;
        public CalculateSymbol(string symbol, byte level, byte requirePara, Action? function) =>
            (this.symbol, this.level, this.requirePara, this.action) = (symbol, level, requirePara, function);
        public CalculateSymbol(CalculateSymbol src) => (symbol, level, requirePara, action) = (src.symbol, src.level, src.requirePara, src.action);
    }



    public class CalculateSymbolCollections
    {
        public CalculateSymbolCollections()
        {
            this._symbolTable = new SortedDictionary<string, CalculateSymbol?>();
        }

        public CalculateSymbolCollections(CalculateSymbol[] symbolTable)
        {
            this._symbolTable = new SortedDictionary<string, CalculateSymbol?>();
            for (int i = 0; i < symbolTable.Count(); i++)
            {
                _symbolTable.Add(symbolTable[i].symbol, symbolTable[i]);
            }
        }

        private SortedDictionary<string, CalculateSymbol?> _symbolTable;
        private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;
        public string[] GetSymbolList()
        {
            string[] array = new string[_symbolTable.Count];
            _symbolTable.Keys.CopyTo(array, 0);
            return array;
        }

        public CalculateSymbol GetSymbol(string symbolName)
        {
            CalculateSymbol? value = default;
            _symbolTable.TryGetValue(symbolName, out value);
            if (value == null)
            {

                throw new UnknowCalculateSymbolException("传入了未知的符号");
            }
            else
            {
                return (CalculateSymbol)value;
            }
        }

        public byte GetSymbolLevel(string symbolName)
        {
            return GetSymbol(symbolName).level;
        }

        public byte GetSymbolRequirePara(string symbolName)
        {
            return GetSymbol(symbolName).requirePara;
        }

        public void appendSymbol(CalculateSymbol s)
        {
            _symbolTable.Add(s.symbol, s);
        }
    }

    public static class CalculateComputer
    {
        public static CalculateSymbol reversePolishcompute(CalculateSymbol[] cal)   //计算逆波兰表达式的函数
        {
            Stack<CalculateSymbol> numStack = new Stack<CalculateSymbol>();
            Stack<CalculateSymbol> symStack = new Stack<CalculateSymbol>();
            CalculateSymbol result;

            // stack.Push(new CalculateSymbol("bottom", 0, 0, null));

            for (int i = 0; i < cal.Count(); i++)
            {

                if (cal[i].action is null)
                {
                    numStack.Push(cal[i]);
                }
                else
                {
                    Byte count = cal[i].requirePara;
                    CalculateSymbol[] num = new CalculateSymbol[count];
                    for (int j = 0; j < count; j++)
                    {
                        num[j] = numStack.Pop();
                    }
                    result = cal[i].action!(num);
                    numStack.Push(result);
                }

            }

            return numStack.Pop();
        }

    }
    class UnknowCalculateSymbolException : Exception
    {
        const string UnknowCalculateSymbolMessage = "所需要的运算符号不存在或无法找到";
        public UnknowCalculateSymbolException(string auxMessage) : base(String.Format("{0}——{1}", UnknowCalculateSymbolMessage, auxMessage)) { }

    }

    static class Exchange
    {
        public static void swap(Object a, object b)
        {
            object temp;
            temp = b;
            b = a;
            a = temp;
        }
        public static T[] assemble<T>(T[] a, int need, int seed)
        {
            T[] obj = new T[need];
            int section = 1;
            for (int i = 0; i < need; i++)
            {
                section *= a.Length;
            }
            seed %= section;

            int index;
            for (int i = 0; i < need; i++)
            {
                section /= a.Length;
                index = seed / section;
                seed %= section;
                obj[i] = a[index];
            }

            return obj;
        }
        public static T[] Permutation<T>(T[] a, int need, int seed)
        {
            T[] obj = new T[need];
            List<T> list = new List<T>(a);

            int section = 1;
            for (int i = 0; i < need; i++)
            {
                section *= a.Length - i;
            }
            seed %= section;

            int index;
            for (int i = 0; i < need; i++)
            {
                section /= (a.Length - i);
                index = seed / section;
                seed %= section;
                obj[i] = list[index];
                list.RemoveAt(index);
            }

            return obj;
        }
    }
}

